package com.googlecode.gwtbb.server.service;

import com.googlecode.gwtbb.client.shared.GwtbbSmess;
import com.googlecode.gwtbb.client.shared.remote.ClientResponse;
import com.googlecode.gwtbb.client.shared.util.StringUtils;
import com.googlecode.gwtbb.server.intermediate.FileOrganizer;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileUploadException;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.web.HttpRequestHandler;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.List;

/**
 * Sample successful format:
 * ok|1|2009/01/18/myfile.txt|additionalInfoCouldBeAnyString
 * Sample error format:
 * error||There was a problem communicating with the server.  Please try refreshing the page.|
 *
 * @author Abraham Grief
 * @version $Id$
 * @since Aug 2, 2008
 */
@SuppressWarnings("unchecked")
public class FileUploadService implements HttpRequestHandler {
	private static Log log = LogFactory.getLog(FileUploadService.class);
	// todo spring configure
	// todo are these thread-safe?
	ServletFileUpload upload = new ServletFileUpload(new DiskFileItemFactory());
	private String contentType = "text/plain";
	private FileOrganizer fileOrganizer;

	public FileOrganizer getFileOrganizer() {
		return fileOrganizer;
	}

	public void setFileOrganizer(FileOrganizer fileOrganizer) {
		this.fileOrganizer = fileOrganizer;
	}

	public void handleRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		response.setContentType(contentType);
		String fileKey = null;

		if (ServletFileUpload.isMultipartContent(request)) {
			FileItem uploadItem = null;

			try {
				List<FileItem> items = upload.parseRequest(request);
				for (FileItem fileItem : items) {
					final boolean isFormField = fileItem.isFormField();
					final String fieldName = fileItem.getFieldName();
					if (!isFormField && ClientResponse.FILE_UPLOAD.equals(fieldName))
						uploadItem = fileItem;
					else if (isFormField && ClientResponse.FILE_KEY.equals(fieldName))
						fileKey = fileItem.getString();
				}
			} catch (FileUploadException e) {
				log.warn(e);
			}

			if (uploadItem != null) {
				File file = fileOrganizer.writeFile(uploadItem);
				PrintWriter writer = response.getWriter();
				writer.write(ClientResponse.OK);
				writer.write(ClientResponse.TEXT_DELIM);
				if (fileKey != null)
					writer.write(fileKey);
				writer.write(ClientResponse.TEXT_DELIM);
				String organizedPath = fileOrganizer.getOrganizedPath(file);
				// Even if we're on windows, we return unix-style paths to the client.
				// We do this to avoid having code on the client that is server-os dependent,
				// which we would need for fakeUpload.
				if (File.separatorChar != StringUtils.URL_SEPARATOR_CHAR)
					organizedPath = organizedPath.replace(File.separatorChar, StringUtils.URL_SEPARATOR_CHAR);
				writer.write(organizedPath);
				writer.write(ClientResponse.TEXT_DELIM);
				writer.write(fileOrganizer.getAdditionalInfo(file));
				return;
			}
		}

		badRequest(response, fileKey);
	}

	private static void badRequest(HttpServletResponse response, String fileKey) throws IOException {
		PrintWriter writer = response.getWriter();
		writer.write(ClientResponse.ERROR);
		writer.write(ClientResponse.TEXT_DELIM);
		if (fileKey != null)
			writer.write(fileKey);
		writer.write(ClientResponse.TEXT_DELIM);
		writer.write(GwtbbSmess.instance().badRequest());
		writer.write(ClientResponse.TEXT_DELIM);
	}
}
